package
{
	import com.indiemaps.mapping.data.parsers.e00.E00Parser;
	import com.indiemaps.mapping.data.parsers.e00.E00Tools;
	import com.indiemaps.mapping.projections.LambertConformalConic;
	
	import flash.display.Graphics;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.ColorTransform;
	import flash.geom.Rectangle;
	import flash.net.URLLoader;
	import flash.net.URLLoaderDataFormat;
	import flash.net.URLRequest;
	import flash.utils.Dictionary;
	
	/**
	 * An application of the E00Parser and E00Tools classes which takes advantage of the topological nature of the data format to show feature neighbors on mouseover.
	 * Loads, projects, and draws an e00 file of the United States at run-time.
	 * Note: loading/projecting/drawing may take up to a couple dozen seconds (though should only take a few).  
	 * No progress bar or status indicators are included in the example. */
	[SWF(backgroundColor='#ffffff', width='1000', height='500')]
	public class E00MouseoverExample extends Sprite
	{
		
		protected static const BOUNDS : Rectangle = new Rectangle( 0, 0, 600, 500 );
		
		protected static var STANDARD_PARALLEL_1 : Number = 33.7;
		protected static var STANDARD_PARALLEL_2 : Number = 35.8;
		protected static var LATITUDE_ORIGIN : Number = 34.7;
		protected static var LONGITUDE_ORIGIN : Number = -92.4;
		
		private var e00Location : String = 'data/e00/st99_d00.e00';
		
		private var mapContainer : Sprite = new Sprite();
		
		private var featureSprites : Dictionary;
		private var featureNeighbors : Dictionary;
		private var featureKeys : Dictionary;
		
		public function E00MouseoverExample()
		{
			addChild( mapContainer );
			mapContainer.y = 50;
			
			// load e00 data
			var dataLoader:URLLoader = new URLLoader();
			dataLoader.dataFormat = URLLoaderDataFormat.TEXT;
			dataLoader.load( new URLRequest( e00Location ) );
			dataLoader.addEventListener( Event.COMPLETE, onE00LoadingComplete );
		}
		
		private function onE00LoadingComplete( e : Event ) : void
		{
			var e00Text : String = e.target.data as String;
			
			// parse the e00 ascii file text
			var data : Object = E00Parser.parse( e00Text );
			
			// get a dictionary of the drawn features, projected in lambert's conformal conic	
			featureSprites = E00Tools.drawAllFeatures( data, data[ 'ifo' ][ 'PAT' ][ 'data' ], 'STATE', projectionFunction, BOUNDS.width, BOUNDS.height, null, [ '02', '', 72, 15 ] );
			var featureStrokes : Dictionary = E00Tools.drawAllFeatures( data, data[ 'ifo' ][ 'PAT' ][ 'data' ], 'STATE', projectionFunction, BOUNDS.width, BOUNDS.height, 
				function( graphics : Graphics ) : void { graphics.lineStyle( 1, 0xdddddd, 1 ); }, [ '02', '', 72, 15 ] );
			// get a dictionary of the *projected* feature centroids
			featureNeighbors = E00Tools.getAllFeatureNeighbors( data, data[ 'ifo' ][ 'PAT' ][ 'data' ], 'STATE' );
			
			// features are already scaled and positioned correctly (based on bounds specified above) and need only be added to the display list
			for each ( var featureSprite : Object in featureSprites ) {
				// the returned featureSprites Dictionary contains only Sprites save for 3 numeric properties: 'zoom', 'xAdjustment', and 'yAdjustment'
				if ( featureSprite is Sprite )
					mapContainer.addChild( featureSprite as Sprite );
			}
			
			// let's not forget those strokes
			for each ( featureSprite in featureStrokes ) {
				// the returned featureSprites Dictionary contains only Sprites save for 3 numeric properties: 'zoom', 'xAdjustment', and 'yAdjustment'
				if ( featureSprite is Sprite )
					mapContainer.addChild( featureSprite as Sprite );
			}
			makeFeaturesInteractive( featureSprites, featureNeighbors );
		}
		
		private function makeFeaturesInteractive( featureSprites : Dictionary, featureNeighbors : Dictionary ) : void
		{
			// this is a look-up dictionary for feature keys
			featureKeys = new Dictionary();
			
			for ( var key : Object in featureSprites ) {
				if ( ! (featureSprites[ key ] is Sprite) ) continue;
				var featureSprite : Sprite = featureSprites[ key ];
				
				// add this feature's key to the dictionary with the feature's sprite as the key
				featureKeys[ featureSprite ] = key;
				
				// add listeners for mouseover/out
				featureSprite.addEventListener( MouseEvent.MOUSE_OVER, onFeatureMouseOver );
				featureSprite.addEventListener( MouseEvent.MOUSE_OUT, onFeatureMouseOut );
			}
		}
		
		private function onFeatureMouseOver( e : MouseEvent ) : void
		{
			var feature : Sprite;
			feature = e.target as Sprite;
			
			// get all the feature keys for the moused-over feature neighbors
			var nbors : Array = featureNeighbors[ featureKeys[ feature ] ];
			// color the over sprite
			var ct : ColorTransform = new ColorTransform();
			
			// color the neighbors
			for each ( var neighbor : String in nbors ) {
				if ( neighbor == '' ) continue;
				
				// first, color the neighbor's neighbors
				ct.color = 0x666666;
				for each ( var neighborsNeighbor : String in featureNeighbors[ neighbor ] ) {
					if ( nbors.indexOf( Number(neighborsNeighbor) ) != -1 || nbors.indexOf( neighborsNeighbor ) != -1 ) continue;
					if ( neighborsNeighbor == '' ) continue;
					feature = featureSprites[ neighborsNeighbor ];
					if ( feature == null ) continue;
					feature.transform.colorTransform = ct;
				}
				
				// then the neighbor
				ct.color = 0x333333;
				feature = featureSprites[ neighbor ];
				if ( feature == null ) continue;
				feature.transform.colorTransform = ct;
			}
			
			ct.color = 0xEC087D;
			feature = e.target as Sprite;
			feature.transform.colorTransform = ct;
		}
		
		private function onFeatureMouseOut( e : MouseEvent ) : void
		{
			var feature : Sprite = e.target as Sprite;
			
			// get all the feature keys for the moused-over feature neighbors
			var nbors : Array = featureNeighbors[ featureKeys[ feature ] ];
			
			// color the out of sprite
			var ct : ColorTransform = new ColorTransform();
			ct.color = 0xcccccc;
			
			feature.transform.colorTransform = ct;
			
			// color the neighbors
			for each ( var neighbor : Object in nbors ) {
				if ( neighbor == '' ) continue;
				
				for each ( var neighborsNeighbor : String in featureNeighbors[ neighbor ] ) {
					if ( neighborsNeighbor == '' ) continue;
					feature = featureSprites[ neighborsNeighbor ];
					if ( feature == null ) continue;
					feature.transform.colorTransform = ct;
				}
				feature = featureSprites[ neighbor ];
				if ( feature == null ) continue;
				feature.transform.colorTransform = ct;
			}
		}
		
		// uses my LambertConformalConic projection class, a projection often used to display the continental U.S.A.
		private function projectionFunction( point : Object ) : Object
		{	
			return LambertConformalConic.projectPoint( point.y, point.x, 1000, -1000, 500, -500, STANDARD_PARALLEL_1, STANDARD_PARALLEL_2, LATITUDE_ORIGIN, LONGITUDE_ORIGIN );
		}
	}
}